/**
 * Dies ist die Root-Klasse for alle Widgets.
 */

package jcurses.widgets;

import jcurses.system.CharColor;
import jcurses.util.Rectangle;

/**
 * This class is superclass for all jcurses widgets. For implementing a ne
 * widget you must derive it.
 * 
 * An jcurses widget is already used within a window. Its task ist to help it's
 * <code>WidgetContainer</code> to layout itself, giving needed informations, to
 * paint itself and to handle input. Handling input is needed only, if the
 * widget has is an input widget ( examples are text input widget, list widget)
 * and has currently focus, that is is selected by user to handle input. This
 * selectig ocurrs by typing a special key (currenty 'tab') to switch between
 * input widgets.
 * 
 * All widgets are ordered in a hierarchy. An widget is already has a container,
 * if it isn't the root pane of a window.
 */
public abstract class Widget {

	WidgetContainer _parent = null;
	Window _window = null;

	private int _x = 0;

	private int _y = 0;

	private Rectangle _size;

	private boolean _visible = true;

	private CharColor _colors = null;
	private static CharColor __defaultColors = new CharColor(CharColor.WHITE,
			CharColor.WHITE);

	/**
	 * @return colors of the widget
	 */
	public CharColor getColors() {
		return (_colors == null) ? getDefaultColors() : _colors;
	}

	/**
	 * The method returns true, if the visibility flag of the widget is true.
	 * This doesn't mean that the widget ist currently visible, because the
	 * parent whole window can be unvisible, use the method
	 * <code>isVisible</code> to query the visisbility
	 * 
	 * @return true, if the visibility flag is set, false otherwise
	 */
	public boolean getVisible() {
		return _visible;
	}

	/**
	 * return true, if the widget is currently visible, false otherwise.
	 * 
	 */
	public boolean isVisible() {
		Widget parent = getParent();
		if ((parent != null) && (!(parent.isVisible()))) {
			return false;
		}
		Window w = getWindow();
		boolean result = ((_visible) && (w != null) && (w.isVisible()));
		return result;
	}

	/**
	 * Set colors of the widget
	 * 
	 * @param colors
	 *            new colors
	 * 
	 */
	public void setColors(CharColor colors) {
		_colors = colors;
	}

	/**
	 * The method manages visibility
	 * 
	 * @param visible
	 *            true, if the widget is to make visible, false otherwise.
	 */
	public void setVisible(boolean visible) {
		_visible = visible;
	}

	/**
	 * This method paints the widget. Will be called by <code>paint()<code>,
	 * only if the widget is visible. Must be implemented be derived classes.
	 */
	protected abstract void doPaint();

	/**
	 * This method repaints the widget. Will be called by <code>paint()<code>,
	 * only if the widget is visible. Must be implemented be derived classes.
	 */
	protected abstract void doRepaint();

	/**
	 * @return x coordinate on the screen
	 */
	protected int getAbsoluteX() {
		int result = 0;
		if (getParent() == null) {
			result = _x;
		} else {
			result = _x + getParent().getAbsoluteX();
			if (getParent().getChildsRectangle() != null) {
				result = result + getParent().getChildsRectangle().getX();
			}
		}

		return result;
	}

	/**
	 * @return y coordinate on the screen
	 */
	protected int getAbsoluteY() {
		int result = 0;
		if (getParent() == null) {
			result = _y;
		} else {
			result = _y + getParent().getAbsoluteY();
			if (getParent().getChildsRectangle() != null) {
				result = result + getParent().getChildsRectangle().getY();
			}
		}

		return result;
	}

	/**
	 * @return default colors for this widget. What this mentiones in a concret
	 *         case, is dependent on the derived class.
	 */
	protected CharColor getDefaultColors() {
		return __defaultColors;
	}

	/**
	 * @return widget's container
	 */
	protected WidgetContainer getParent() {
		return _parent;
	}

	/**
	 * This method gives the widget container the infomation about the preferred
	 * size of this widget. Must be implemented by derived classes.
	 */
	protected abstract Rectangle getPreferredSize();

	/**
	 * Returns the rectangle on the screen, that contains this widget
	 * 
	 * @return the rectangle on the screen, that contains this widget
	 */
	protected Rectangle getRectangle() {
		Rectangle size = (Rectangle) getSize().clone();
		size.setLocation(getAbsoluteX(), getAbsoluteY());
		return size;
	}

	/**
	 * @return widget's size
	 */
	protected Rectangle getSize() {
		Rectangle rec = null;
		if (_size != null) {
			rec = _size.clone();
		}
		return rec;

	}

	/**
	 * @return widget's window
	 */
	protected Window getWindow() {
		if (getParent() == null) {
			return _window;
		} else {
			return getParent().getWindow();
		}
	}

	/**
	 * @return x coordinate within the container
	 */
	protected int getX() {
		return _x;
	}

	/**
	 * @return y coordinate within the container
	 */
	protected int getY() {
		return _y;
	}

	/**
	 * The method is called by the framework to paint the widget
	 */

	protected void paint() {
		if (isVisible()) {
			doPaint();
		}
	}

	/**
	 * The method is called by the framework to repaint the widget
	 */
	protected void repaint() {
		if (isVisible()) {
			doRepaint();
		}
	}

	/**
	 * Sets widget's container. Is called by framework, schouldn't be called
	 * writing applications
	 * 
	 * @param parent
	 *            new container
	 */
	protected void setParent(WidgetContainer parent) {
		_parent = parent;
	}

	/**
	 * Sets the size of the widget.
	 * 
	 * @param size
	 *            new size
	 */
	protected void setSize(Rectangle size) {
		_size = size;

	}

	/**
	 * /** Sets widget's window. Is called by framework, schouldn't be called
	 * writing applications
	 * 
	 * @param window
	 *            widget's window
	 */
	protected void setWindow(Window window) {
		_window = window;
	}

	/**
	 * Sets the x coordinate within the container. Is called by framework,
	 * schouldn't be called writing applications
	 * 
	 * @param x
	 *            x coordinate within the container
	 */
	protected void setX(int x) {
		_x = x;
	}

	/**
	 * Sets the y coordinate within the container. Is called by framework,
	 * schouldn't be called writing applications
	 * 
	 * @param y
	 *            y coordinate within the container
	 */
	protected void setY(int y) {
		_y = y;
	}

}
